home *** CD-ROM | disk | FTP | other *** search
/ Aminet 5 / Aminet 5 - March 1995.iso / Aminet / gfx / pbm / pcxtoppm.lha / src / ppmtopcx.c < prev   
C/C++ Source or Header  |  1994-12-12  |  12KB  |  443 lines

  1. /* ppmtopcx.c - convert a portable pixmap to PCX
  2. **
  3. ** Copyright (C) 1994 by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
  4. ** based on ppmtopcx.c by Michael Davidson
  5. **
  6. ** Permission to use, copy, modify, and distribute this software and its
  7. ** documentation for any purpose and without fee is hereby granted, provided
  8. ** that the above copyright notice appear in all copies and that both that
  9. ** copyright notice and this permission notice appear in supporting
  10. ** documentation.  This software is provided "as is" without express or
  11. ** implied warranty.
  12. **
  13. ** 11/Dec/94: first version
  14. ** 12/Dec/94: added support for "packed" format (16 colors or less)
  15. */
  16. #include "ppm.h"
  17. #include "ppmcmap.h"
  18.  
  19. /*#define DEBUG*/
  20.  
  21. #define MAXCOLORS       256
  22.  
  23. #define PCX_MAGIC       0x0a            /* PCX magic number             */
  24. #define PCX_256_COLORS  0x0c            /* magic number for 256 colors  */
  25. #define PCX_MAXVAL      (pixval)255
  26.  
  27.  
  28. /* prototypes */
  29. static void ppm_to_16col_pcx ARGS((pixel **pixels, int cols, int rows,
  30.                                    pixel *cmap, int colors, colorhash_table cht));
  31. static void ppm_to_256col_pcx ARGS((pixel **pixels, int cols, int rows,
  32.                                    pixel *cmap, int colors, colorhash_table cht));
  33. static void ppm_to_truecol_pcx ARGS((pixel **pixels, int cols, int rows, int maxval));
  34. static void write_header ARGS((FILE *fp, int cols, int rows, int BitsPerPixel, int Planes, pixel *cmap16));
  35. static void PCXEncode ARGS(( FILE* fp, unsigned char* buf, int Size ));
  36. static void ToPlanes ARGS((unsigned char *rawrow, int width, unsigned char *buf, int planes));
  37. static void PackBits ARGS((unsigned char *rawrow, int width, unsigned char *buf, int bits));
  38. static void Putword ARGS(( int w, FILE* fp ));
  39. static void Putbyte ARGS(( int b, FILE* fp ));
  40.  
  41. static short force24 = 0;
  42. static short packbits = 0;
  43.  
  44.  
  45. int
  46. main( argc, argv )
  47.     int argc;
  48.     char* argv[];
  49.     {
  50.     FILE* ifp;
  51.     int argn, rows, cols, colors, i;
  52.     pixval maxval;
  53.     pixel black_pixel, *cmap, **pixels;
  54.     colorhist_vector chv;
  55.     colorhash_table cht;
  56.     char* usage = "[-24bit] [-packed] [ppmfile]";
  57.  
  58.     ppm_init(&argc, argv);
  59.  
  60.     argn = 1;
  61.     while( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) {
  62.         if( pm_keymatch(argv[argn], "-24bit", 3) )
  63.             force24 = 1;
  64.         else
  65.         if( pm_keymatch(argv[argn], "-packed", 2) )
  66.             packbits = 1;
  67.         else
  68.             pm_usage(usage);
  69.         ++argn;
  70.     }
  71.     if( argn < argc ) {
  72.         ifp    = pm_openr(argv[argn]);
  73.         ++argn;
  74.     }
  75.     else
  76.         ifp    = stdin;
  77.     if( argn != argc )
  78.         pm_usage(usage);
  79.  
  80.  
  81.     pixels = ppm_readppm( ifp, &cols, &rows, &maxval );
  82.     pm_close( ifp );
  83.  
  84.     if( !force24 ) {
  85.         /* Figure out the colormap. */
  86.         pm_message( "computing colormap..." );
  87.         chv = ppm_computecolorhist( pixels, cols, rows, MAXCOLORS, &colors );
  88.         if ( chv == (colorhist_vector) 0 ) {
  89.             pm_message("too many colors - writing a 24bit PCX file");
  90.             pm_message("if you want a non-24bit file, do a \'ppmquant %d\'", MAXCOLORS);
  91.             force24 = 1;
  92.         }
  93.     }
  94.  
  95.     if( maxval != PCX_MAXVAL )
  96.         pm_message("maxval is not %d - automatically rescaling colors", PCX_MAXVAL);
  97.  
  98.     if( force24 )
  99.         ppm_to_truecol_pcx(pixels, cols, rows, maxval);
  100.     else {
  101.         pm_message("%d colors found", colors);
  102.  
  103.         /* Force black to slot 0 if possible. */
  104.         PPM_ASSIGN(black_pixel, 0, 0, 0 );
  105.         ppm_addtocolorhist(chv, &colors, MAXCOLORS, &black_pixel, 0, 0 );
  106.  
  107.  
  108.         /* build colormap */
  109.         cmap = ppm_allocrow(MAXCOLORS);
  110.         for( i = 0; i < colors; i++ ) {
  111.             pixval r, g, b;
  112.             r = PPM_GETR(chv[i].color); g = PPM_GETG(chv[i].color); b = PPM_GETB(chv[i].color);
  113.             if( maxval != PCX_MAXVAL ) {
  114.                 r = r * PCX_MAXVAL / maxval; g = g * PCX_MAXVAL / maxval; b = b * PCX_MAXVAL / maxval;
  115.             }
  116.             PPM_ASSIGN(cmap[i], r, g, b);
  117.         }
  118.         for( ; i < MAXCOLORS; i++ )
  119.             PPM_ASSIGN(cmap[i], 0,0,0);
  120.  
  121.         /* make a hash table for fast color lookup */
  122.         cht = ppm_colorhisttocolorhash(chv, colors);
  123.         ppm_freecolorhist( chv );
  124.  
  125.         /* convert image */
  126.         if( colors <= 16 )
  127.             ppm_to_16col_pcx(pixels, cols, rows, cmap, colors, cht);
  128.         else
  129.             ppm_to_256col_pcx(pixels, cols, rows, cmap, colors, cht);
  130.     }
  131.     exit(0);
  132. }
  133.  
  134.  
  135. static void
  136. ppm_to_16col_pcx(pixels, cols, rows, cmap, colors, cht)
  137.     pixel **pixels;
  138.     int cols, rows;
  139.     pixel *cmap;
  140.     int colors;
  141.     colorhash_table cht;
  142. {
  143.     int Planes, BytesPerLine, BitsPerPixel;
  144.     unsigned char *rawrow, *planesrow;
  145.     register int col, row;
  146.  
  147. #ifdef DEBUG
  148.     pm_message("ppm -> %d colors", colors);
  149. #endif
  150.  
  151.     if( packbits ) {
  152.         Planes = 1;
  153.         if( colors > 4 )        BitsPerPixel = 4;
  154.         else if( colors > 2 )   BitsPerPixel = 2;
  155.         else                    BitsPerPixel = 1;
  156.     }
  157.     else {
  158.         BitsPerPixel = 1;
  159.         if( colors > 8 )        Planes = 4;
  160.         else if( colors > 4 )   Planes = 3;
  161.         else if( colors > 2 )   Planes = 2;
  162.         else                    Planes = 1;
  163.     }
  164.  
  165.     BytesPerLine    = ((cols * BitsPerPixel) + 7) / 8;
  166.     rawrow = (unsigned char *)pm_allocrow(cols, sizeof(unsigned char));
  167.     planesrow = (unsigned char *)pm_allocrow(BytesPerLine, sizeof(unsigned char));
  168.  
  169. #ifdef DEBUG
  170.     pm_message("Planes = %d, BitsPerPixel = %d, BytesPerLine = %d",
  171.                 Planes, BitsPerPixel, BytesPerLine);
  172. #endif
  173.  
  174.     write_header(stdout, cols, rows, BitsPerPixel, Planes, cmap);
  175.     for( row = 0; row < rows; row++ ) {
  176.         register pixel *pP = pixels[row];
  177.         for( col = 0; col < cols; col++, pP++ )
  178.             rawrow[col] = (unsigned char)ppm_lookupcolor(cht, pP) & 0x0f;
  179.         if( packbits ) {
  180.             PackBits(rawrow, cols, planesrow, BitsPerPixel);
  181.             PCXEncode(stdout, planesrow, BytesPerLine);
  182.         }
  183.         else {
  184.             for( col = 0; col < Planes; col++ ) {
  185.                 ToPlanes(rawrow, cols, planesrow, col);
  186.                 PCXEncode(stdout, planesrow, BytesPerLine);
  187.             }
  188.         }
  189.     }
  190. #ifdef DEBUG
  191.     pm_message("done!");
  192. #endif
  193.     pm_freerow(planesrow);
  194.     pm_freerow(rawrow);
  195. }
  196.  
  197.  
  198. static void
  199. ppm_to_256col_pcx(pixels, cols, rows, cmap, colors, cht)
  200.     pixel **pixels;
  201.     int cols, rows;
  202.     pixel *cmap;
  203.     int colors;
  204.     colorhash_table cht;
  205. {
  206.     register int col, row, i;
  207.     unsigned char *rawrow;
  208.  
  209. #ifdef DEBUG
  210.     pm_message("ppm -> 256 color, writing index array...");
  211. #endif
  212.  
  213.     rawrow = (unsigned char *)pm_allocrow(cols, sizeof(unsigned char));
  214.  
  215.     /* 8 bits per pixel, 1 plane */
  216.     write_header(stdout, cols, rows, 8, 1, (pixel *)NULL);
  217.     for( row = 0; row < rows; row++ ) {
  218.         register pixel *pP = pixels[row];
  219.         for( col = 0; col < cols; col++, pP++ )
  220.             rawrow[col] = ppm_lookupcolor(cht, pP);
  221.         PCXEncode(stdout, rawrow, cols);
  222.     }
  223. #ifdef DEBUG
  224.     pm_message("ok, writing colormap...");
  225. #endif
  226.     Putbyte(PCX_256_COLORS, stdout);
  227.     for( i = 0; i < MAXCOLORS; i++ ) {
  228.         Putbyte(PPM_GETR(cmap[i]), stdout);
  229.         Putbyte(PPM_GETG(cmap[i]), stdout);
  230.         Putbyte(PPM_GETB(cmap[i]), stdout);
  231.     }
  232. #ifdef DEBUG
  233.     pm_message("done!");
  234. #endif
  235.     pm_freerow(rawrow);
  236. }
  237.  
  238.  
  239. static void
  240. ppm_to_truecol_pcx(pixels, cols, rows, maxval)
  241.     pixel **pixels;
  242.     int cols, rows, maxval;
  243. {
  244.     unsigned char *redrow, *greenrow, *bluerow;
  245.     register int col, row;
  246.  
  247. #ifdef DEBUG
  248.     pm_message("ppm -> 24bit");
  249. #endif
  250.  
  251.     redrow   = (unsigned char *)pm_allocrow(cols, sizeof(unsigned char));
  252.     greenrow = (unsigned char *)pm_allocrow(cols, sizeof(unsigned char));
  253.     bluerow  = (unsigned char *)pm_allocrow(cols, sizeof(unsigned char));
  254.  
  255.     /* 8 bits per pixel, 3 planes */
  256.     write_header(stdout, cols, rows, 8, 3, (pixel *)NULL);
  257.     for( row = 0; row < rows; row++ ) {
  258.         register pixel *pP = pixels[row];
  259.         for( col = 0; col < cols; col++, pP++ ) {
  260.             if( maxval != PCX_MAXVAL ) {
  261.                 redrow[col]   = (long)PPM_GETR(*pP) * PCX_MAXVAL / maxval;
  262.                 greenrow[col] = (long)PPM_GETG(*pP) * PCX_MAXVAL / maxval;
  263.                 bluerow[col]  = (long)PPM_GETB(*pP) * PCX_MAXVAL / maxval;
  264.             }
  265.             else {
  266.                 redrow[col]   = PPM_GETR(*pP);
  267.                 greenrow[col] = PPM_GETG(*pP);
  268.                 bluerow[col]  = PPM_GETB(*pP);
  269.             }
  270.         }
  271.         PCXEncode(stdout, redrow, cols);
  272.         PCXEncode(stdout, greenrow, cols);
  273.         PCXEncode(stdout, bluerow, cols);
  274.     }
  275. #ifdef DEBUG
  276.     pm_message("done!");
  277. #endif
  278.     pm_freerow(bluerow);
  279.     pm_freerow(greenrow);
  280.     pm_freerow(redrow);
  281. }
  282.  
  283.  
  284. static void
  285. write_header(fp, cols, rows, BitsPerPixel, Planes, cmap16)
  286.     FILE *fp;
  287.     int cols, rows;
  288.     int BitsPerPixel, Planes;
  289.     pixel *cmap16;
  290. {
  291.     int i, BytesPerLine;
  292.  
  293.     Putbyte( PCX_MAGIC, fp);        /* .PCX magic number            */
  294.     Putbyte( 0x05, fp);             /* PC Paintbrush version        */
  295.     Putbyte( 0x01, fp);             /* .PCX run length encoding     */
  296.     Putbyte( BitsPerPixel, fp);     /* bits per pixel               */
  297.  
  298.     Putword( 0, fp );               /* x1   - image left            */
  299.     Putword( 0, fp );               /* y1   - image top             */
  300.     Putword( cols-1, fp );          /* x2   - image right           */
  301.     Putword( rows-1, fp );          /* y2   - image bottom          */
  302.  
  303.     Putword( cols, fp );            /* horizontal resolution        */
  304.     Putword( rows, fp );            /* vertical resolution          */
  305.  
  306.     /* Write out the Color Map for images with 16 colors or less */
  307.     if( cmap16 )
  308.         for (i = 0; i < 16; ++i) {
  309.             Putbyte( PPM_GETR(cmap16[i]), fp );
  310.             Putbyte( PPM_GETG(cmap16[i]), fp );
  311.             Putbyte( PPM_GETB(cmap16[i]), fp );
  312.         }
  313.     else
  314.         for (i = 0; i < 16; ++i) {
  315.             Putbyte( 0, fp );
  316.             Putbyte( 0, fp );
  317.             Putbyte( 0, fp );
  318.         }
  319.  
  320.     Putbyte( 0, fp);                /* reserved byte                */
  321.     Putbyte( Planes, fp);           /* number of color planes       */
  322.  
  323.     BytesPerLine    = ((cols * BitsPerPixel) + 7) / 8;
  324.     Putword( BytesPerLine, fp );    /* number of bytes per scanline */
  325.  
  326.     Putword( 1, fp);                /* pallette info                */
  327.  
  328.     for (i = 0; i < 58; ++i)        /* fill to end of header        */
  329.         Putbyte( 0, fp );
  330. }
  331.  
  332.  
  333. static void
  334. PCXEncode(fp, buf, Size)
  335. FILE            *fp;
  336. unsigned char   *buf;
  337. int             Size;
  338. {
  339.     unsigned char   *end;
  340.     int c, previous, count;
  341.  
  342.     end = buf + Size;
  343.     previous = *buf++;
  344.     count    = 1;
  345.  
  346.     while (buf < end) {
  347.         c = *buf++;
  348.         if (c == previous && count < 63) {
  349.             ++count;
  350.             continue;
  351.         }
  352.  
  353.         if (count > 1 || (previous & 0xc0) == 0xc0) {
  354.             count |= 0xc0;
  355.             Putbyte ( count , fp );
  356.         }
  357.         Putbyte(previous, fp);
  358.         previous = c;
  359.         count   = 1;
  360.     }
  361.  
  362.     if (count > 1 || (previous & 0xc0) == 0xc0) {
  363.         count |= 0xc0;
  364.         Putbyte ( count , fp );
  365.     }
  366.     Putbyte(previous, fp);
  367. }
  368.  
  369.  
  370. static void
  371. PackBits(rawrow, width, buf, bits)
  372.     unsigned char *rawrow;
  373.     int width;
  374.     unsigned char *buf;
  375.     int bits;
  376. {
  377.     register int x, i, shift;
  378.  
  379.     shift = i = -1;
  380.     for( x = 0; x < width; x++ ) {
  381.         if( shift < 0 ) {
  382.             shift = 8-bits;
  383.             buf[++i] = 0;
  384.         }
  385.  
  386.         buf[i] |= (rawrow[x] << shift);
  387.         shift -= bits;
  388.     }
  389. }
  390.  
  391.  
  392. static const unsigned char bitmask[] = {1, 2, 4, 8, 16, 32, 64, 128};
  393.  
  394.  
  395. static void
  396. ToPlanes(rawrow, width, buf, plane)
  397.     unsigned char *rawrow;
  398.     int width;
  399.     unsigned char *buf;
  400.     int plane;
  401. {
  402.     int cbit, x, mask;
  403.     unsigned char *cp = buf-1;
  404.  
  405.     mask = 1 << plane;
  406.     cbit = -1;
  407.     for( x = 0; x < width; x++ ) {
  408.         if( cbit < 0 ) {
  409.             cbit = 7;
  410.             *++cp = 0;
  411.         }
  412.         if( rawrow[x] & mask )
  413.             *cp |= bitmask[cbit];
  414.         --cbit;
  415.     }
  416. }
  417.  
  418.  
  419. /*
  420.  * Write out a word to the PCX file
  421.  */
  422. static void
  423. Putword( w, fp )
  424. int w;
  425. FILE *fp;
  426. {
  427.     Putbyte( w & 0xff, fp );
  428.     Putbyte( (w / 256) & 0xff, fp );
  429. }
  430.  
  431. /*
  432.  * Write out a byte to the PCX file
  433.  */
  434. static void
  435. Putbyte( b, fp )
  436. int b;
  437. FILE *fp;
  438. {
  439.     if( fputc( b & 0xff, fp ) == EOF )
  440.         pm_error("write error");
  441. }
  442.  
  443.